package com.kiragame.couplescreen.quickblox;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

import org.jivesoftware.smack.ConnectionListener;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Message.Type;

import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Environment;
import android.support.v4.content.LocalBroadcastManager;

import com.kiragame.couplescreen.DataManager;
import com.kiragame.couplescreen.KiraMessage;
import com.kiragame.couplescreen.KiraMessage.MessageType;
import com.kiragame.couplescreen.utils.KiraGameLog;
import com.quickblox.core.QBCallback;
import com.quickblox.core.QBCallbackImpl;
import com.quickblox.core.QBSettings;
import com.quickblox.core.result.Result;
import com.quickblox.module.auth.QBAuth;
import com.quickblox.module.chat.QBChatService;
import com.quickblox.module.chat.listeners.ChatMessageListener;
import com.quickblox.module.chat.listeners.SessionCallback;
import com.quickblox.module.chat.smack.SmackAndroid;
import com.quickblox.module.chat.xmpp.QBPrivateChat;
import com.quickblox.module.content.QBContent;
import com.quickblox.module.content.model.QBFile;
import com.quickblox.module.content.result.QBFileUploadTaskResult;
import com.quickblox.module.users.QBUsers;
import com.quickblox.module.users.model.QBUser;

public class QuickBloxManager implements ChatMessageListener {
	public static final String ACTION_CHANGE_UI_MAIN = "com.kiragame.couplescreen.changeuimain";
	public static final String MESSAGE_INFO = "MESSAGE_INFO";
	public static final String ACTION_UI_MAIN = "ACTION_UI_MAIN";
	public static final String ACTION_HIDE_PROGESSBAR = "ACTION_HIDE_PROGESSBAR";
	public static final String ACTION_SHOW_PROGESSBAR = "ACTION_SHOW_PROGESSBAR";
	public static final String ACTION_SHOW_NOTICE = "ACTION_SHOW_NOTICE";
	public static final String ACTION_SHOW_IMAGE = "ACTION_SHOW_IMAGE";
	public static final String ACTION_SHOW_ERROR = "ACTION_SHOW_ERROR";
	private static QuickBloxManager mQuickBloxManager;
	private static boolean isSetupDone = true;
	private Context mContext;

	// QuickBlox
	private static final String APP_ID = "14649";
	private static final String AUTH_KEY = "5msKemGzgL-zjDu";
	private static final String AUTH_SECRET = "NEqNnLZsWyc6eLc";
	private static QBUser qbUser = null;
	private SmackAndroid smackAndroid;
	private final String PASSWORD_DEFAULT = "abcd123456";
	private final String USER_EXIST = "login has already been taken";
	private final String NOT_REGISTER = "Unauthorized";
	private final String HAVE_LOGGED = "You have already logged in Chat!";
	private LocalBroadcastManager broadcaster;
	public static QBPrivateChat chat = null;

	public static QuickBloxManager getInstance(Context context) {
		if (mQuickBloxManager == null) {
			mQuickBloxManager = new QuickBloxManager(context);
		}
		return mQuickBloxManager;
	}

	public QuickBloxManager(Context context) {
		this.mContext = context;
		broadcaster = LocalBroadcastManager.getInstance(context);
		// setUpServer();
	}

	private void showProgessbar() {
		// try {
		// ((MainActivity) mContext).showProgessbar("Connecting to server...");
		// } catch (Exception e) {
		// e.printStackTrace();
		// }
		isSetupDone = false;
		changeUIMain(ACTION_SHOW_PROGESSBAR, "Connecting to server...");

	}

	private void hideProgessbar() {
		// try {
		// ((MainActivity) mContext).hideProgessbar();
		// } catch (Exception e) {
		// e.printStackTrace();
		// }
		changeUIMain(ACTION_HIDE_PROGESSBAR, null);
		isSetupDone = true;
	}

	private void showNotice(String notice) {
		// try {
		// ((MainActivity) mContext).showNotice(notice);
		// } catch (Exception e) {
		// e.printStackTrace();
		// }
		changeUIMain(ACTION_SHOW_NOTICE, notice);
	}

	public void setUpServer() {
		if (!isSetupDone) {
			return;
		}
		showProgessbar();
		KiraGameLog.d("Checking quickblox setup...");
		smackAndroid = SmackAndroid.init(mContext);
		QBSettings.getInstance().fastConfigInit(APP_ID, AUTH_KEY, AUTH_SECRET);
		QBAuth.createSession(new QBCallback() {

			@Override
			public void onComplete(Result result, Object arg1) {
			}

			@Override
			public void onComplete(Result result) {
				if (result.isSuccess()) {
					KiraGameLog.d("Quickblox setup successful!");
					// checkLogin();
					loginQuickblox();
				} else {
					KiraGameLog
							.d("Quickblox setup Error(s) occurred. Look into DDMS log for details, "
									+ "please. Errors: " + result.getErrors());
					hideProgessbar();
					showNotice("Error! " + result.getErrors().get(0));
				}
			}
		});
	}

	private void loginQuickblox() {
		KiraGameLog.d("Login Quickblox...");
		qbUser = new QBUser(DataManager.getInstance(mContext)
				.getDeviceContactID(), PASSWORD_DEFAULT);
		QBUsers.signIn(qbUser, new QBCallback() {

			@Override
			public void onComplete(Result arg0, Object arg1) {
				// TODO Auto-generated method stub

			}

			@Override
			public void onComplete(Result result) {
				if (result.isSuccess()) {
					// ((App)getApplication()).setQbUser(qbUser);
					QBChatService.getInstance().loginWithUser(qbUser,
							new SessionCallback() {
								@Override
								public void onLoginSuccess() {
									KiraGameLog.d("Login Success...");
									setUpChatConnection();
								}

								@Override
								public void onLoginError(String error) {
									KiraGameLog.d("Login Error " + error);
									if (error.equals(HAVE_LOGGED)) {
										setUpChatConnection();
									} else {
										hideProgessbar();
									}

								}

							});
				} else {
					KiraGameLog
							.d("Login Error(s) occurred. Look into DDMS log for details, "
									+ "please. Errors: " + result.getErrors());
					if (result.getErrors().get(0).equals(NOT_REGISTER)) {
						KiraGameLog.d("User not exist... Register now! ");
						registerQuickblox();
					}
				}
			}
		});
	}

	protected void registerQuickblox() {
		qbUser = new QBUser(DataManager.getInstance(mContext)
				.getDeviceContactID(), PASSWORD_DEFAULT);
		QBUsers.signUpSignInTask(qbUser, new QBCallback() {

			@Override
			public void onComplete(Result arg0, Object arg1) {

			}

			@Override
			public void onComplete(Result result) {
				if (result.isSuccess()) {
					QBChatService.getInstance().loginWithUser(qbUser,
							new SessionCallback() {
								@Override
								public void onLoginSuccess() {
									KiraGameLog.d("Login Success...");
									setUpChatConnection();
								}

								@Override
								public void onLoginError(String error) {
									KiraGameLog.d("Login Error " + error);
									hideProgessbar();
								}
							});
				} else {
					KiraGameLog
							.d("Login Error(s) occurred. Look into DDMS log for details, "
									+ "please. Errors: " + result.getErrors());
					hideProgessbar();
				}
			}
		});
	}

	private void setUpChatConnection() {
		KiraGameLog.d("current userID is " + qbUser.getId());
		DataManager.getInstance(mContext).setUserID(qbUser.getId());
		// menuFragment.showUserID();
		QBChatService.getInstance().startAutoSendPresence(60);
		QBChatService.getInstance().addConnectionListener(
				new ConnectionListener() {

					@Override
					public void reconnectionSuccessful() {
						KiraGameLog.d("reconnection Successful!");
					}

					@Override
					public void reconnectionFailed(Exception arg0) {
						KiraGameLog.d("reconnection Failed");
					}

					@Override
					public void reconnectingIn(int arg0) {
						KiraGameLog.d("reconnecting In");
					}

					@Override
					public void connectionClosedOnError(Exception arg0) {
						KiraGameLog.d("connection Closed On Error");
					}

					@Override
					public void connectionClosed() {
						KiraGameLog.d("connection Closed");
					}
				});

		chat = QBChatService.getInstance().createChat();
		chat.addChatMessageListener(this);
		hideProgessbar();
	}

	public void sendMessage(int to, String message) {
		if (chat == null) {
			return;
		}
		try {
			chat.sendMessage(to, message);
		} catch (XMPPException e) {
			KiraGameLog.d("send message fail: " + e.getMessage());
			e.printStackTrace();
		}
	}

	private void captureScreenAndSendFile(final String sendTo) {
		File file;
		Process sh;
		String screenShot = Environment.getExternalStorageDirectory()
				.toString() + "/img_temp.png";
		KiraGameLog.d("image path " + screenShot);
		try {
			sh = Runtime.getRuntime().exec("su", null, null);
			OutputStream os = sh.getOutputStream();
			os.write(("/system/bin/screencap -p " + screenShot)
					.getBytes("ASCII"));
			os.flush();

			os.close();
			sh.waitFor();
		} catch (IOException e) {
			e.printStackTrace();
			sendImageFail(sendTo,
					"Target device is not rooted. Can't take screenshot!");
			return;
		} catch (InterruptedException e) {
			e.printStackTrace();
			sendImageFail(sendTo,
					"Target device is not rooted. Can't take screenshot!");
			return;
		}

		KiraGameLog.d("capture Screen done!");

		Bitmap image = BitmapFactory.decodeFile(screenShot);
		if (image == null) {
			return;
		}
		int width = image.getWidth();
		int height = image.getHeight();
		float ratio = (float) width / height;
		if (width > 1000) {
			width = 1000;
			height = (int) (width / ratio);
			file = resizeImage(image, width, height, screenShot);
		} else if (height > 1000) {
			height = 1000;
			width = (int) (height * ratio);

			file = resizeImage(image, width, height, screenShot);
		} else {
			file = new File(screenShot);
		}

		if (file == null) {
			return;
		}

		// send image
		QBContent.uploadFileTask(file, true, new QBCallbackImpl() {
			@Override
			public void onComplete(Result result) {
				if (result.isSuccess()) {
					// get uploaded file ID
					QBFileUploadTaskResult res = (QBFileUploadTaskResult) result;
					QBFile qbFile = res.getFile();

					// File public url. Will be null if fileIsPublic=false in
					// query
					String publicUrl = qbFile.getPublicUrl();
					KiraGameLog.d("link file " + publicUrl);
					sendImage(sendTo, publicUrl);
				} else {
					KiraGameLog.d("upload file failed! " + result.getErrors());
					sendImageFail(sendTo, "Can't upload file to server!");
				}
			}
		});
	}

	private File resizeImage(Bitmap image, int width, int height,
			String filePath) {
		File file = new File(filePath);
		image = Bitmap.createScaledBitmap(image, width, height, true);
		if (file.exists()) {
			file.delete();
		}
		FileOutputStream out;
		try {
			out = new FileOutputStream(file);
			image.compress(Bitmap.CompressFormat.PNG, 100, out);
			out.flush();
			out.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			return null;

		} catch (IOException e) {
			e.printStackTrace();
			return null;
		}
		return file;
	}

	protected void sendImage(String sendTo, String publicUrl) {
		KiraGameLog.d("Send file " + publicUrl + " to " + sendTo);
		KiraMessage kiraMessage = new KiraMessage();
		kiraMessage.setMessageType(MessageType.SEND_FILE);
		kiraMessage.setContent(publicUrl);
		sendMessage(Integer.parseInt(sendTo), kiraMessage.toJson());
	}

	protected void sendImageFail(String sendTo, String reason) {
		KiraGameLog.d("Send file fail " + reason);
		KiraMessage kiraMessage = new KiraMessage();
		kiraMessage.setMessageType(MessageType.SEND_FILE);
		kiraMessage.setError(reason);
		sendMessage(Integer.parseInt(sendTo), kiraMessage.toJson());
	}

	public void onDestroy() {
		if (smackAndroid != null) {
			smackAndroid.onDestroy();
		}
		if (chat != null) {
			chat.removeChatMessageListener(this);
		}
	}

	@Override
	public boolean accept(Type type) {
		KiraGameLog.d("message receive type " + type);
		return true;
	}

	@Override
	public void processMessage(Message message) {
		KiraGameLog.d("message receive " + message.getBody() + " from "
				+ message.getFrom());
		// Toast.makeText(
		// mContext,
		// "message receive " + message.getBody() + " from "
		// + message.getFrom(), Toast.LENGTH_LONG).show();

		String content = message.getBody();
		KiraMessage kiraMessage = KiraMessage.fromJsonToKiraMessage(content);
		if (kiraMessage.getMessageType() == MessageType.SEND_REQUEST) {
			KiraGameLog.d("Message Type is " + kiraMessage.getMessageType()
					+ " => Capture Screen");
			String sendTo = message.getFrom().split("-")[0];
			captureScreenAndSendFile(sendTo);
		} else if (kiraMessage.getMessageType() == MessageType.SEND_FILE) {
			if (kiraMessage.getError() == null) {
				KiraGameLog.d("Get image succes => Show Image");
				// try {
				// ((MainActivity) mContext)
				// .showImageContent(kiraMessage.getContent());
				// } catch (Exception e) {
				// e.printStackTrace();
				// }
				changeUIMain(ACTION_SHOW_IMAGE, kiraMessage.getContent());
			} else {
				KiraGameLog.d("Get image fail => Show error "
						+ kiraMessage.getError());
				// try {
				// ((MainActivity) mContext).showGetImageError("Error! "
				// + kiraMessage.getError());
				// } catch (Exception e) {
				// e.printStackTrace();
				// }
				changeUIMain(ACTION_SHOW_ERROR,
						"Error! " + kiraMessage.getError());

			}

		}
	}

	private void changeUIMain(String action, String message) {
		Intent intent = new Intent(ACTION_CHANGE_UI_MAIN);
		intent.putExtra(ACTION_UI_MAIN, action);
		if (message != null) {
			intent.putExtra(MESSAGE_INFO, message);
		}
		broadcaster.sendBroadcast(intent);
	}
}
